#include "bsp_adc.h"
#include "bsp_SysTick.h"
#include "stdio.h"
#include "trace.h"

volatile uint16_t ADCValue[12] = {0};
extern int Gray_sum;
extern double sum;
extern uint8_t cnt_whiteline;
extern uint8_t cnt_whitelineL;
extern uint8_t cnt_whitelineR;

/**
 * @brief 前侧灰度初始化(DMA方式)
 */
void ADC1_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // 使能GPIOA时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); // 使能GPIOC时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);  // 使能ADC1时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);  // 使能DMA

    // 初始化ADC1的通道口
    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5; // PA0-PA5
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;                                                                // 模拟输入
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;                                                            // 不带上下拉
    GPIO_Init(GPIOA, &GPIO_InitStructure);                                                                      // 初始化

    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5; // PC0-PC5
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;                                                                // 模拟输入
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;                                                            // 不带上下拉
    GPIO_Init(GPIOC, &GPIO_InitStructure);                                                                      // 初始化

    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, ENABLE);  // ADC1复位
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, DISABLE); // 复位结束

    ADC_CommonInitStructure.ADC_Mode             = ADC_Mode_Independent;         // 独立模式
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; // 两个采样阶段之间的延迟5个时钟
    ADC_CommonInitStructure.ADC_DMAAccessMode    = ADC_DMAAccessMode_2;          // DMA使能
    ADC_CommonInitStructure.ADC_Prescaler        = ADC_Prescaler_Div4;           // 预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz
    ADC_CommonInit(&ADC_CommonInitStructure);                                    // 初始化

    ADC_InitStructure.ADC_Resolution           = ADC_Resolution_12b;            // 12位模式
    ADC_InitStructure.ADC_ScanConvMode         = ENABLE;                        // 扫描模式
    ADC_InitStructure.ADC_ContinuousConvMode   = ENABLE;                        // 连续转换
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; // 禁止触发检测，使用软件触发

    ADC_InitStructure.ADC_ExternalTrigConv = 0;
    ADC_InitStructure.ADC_DataAlign        = ADC_DataAlign_Right; // 右对齐
    ADC_InitStructure.ADC_NbrOfConversion  = 12;                  // 1个转换在规则序列中 也就是只转换规则序列1
    ADC_Init(ADC1, &ADC_InitStructure);                           // ADC初始化

    ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_480Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_480Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_480Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_480Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 5, ADC_SampleTime_480Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 6, ADC_SampleTime_480Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 7, ADC_SampleTime_480Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 8, ADC_SampleTime_480Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 9, ADC_SampleTime_480Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 10, ADC_SampleTime_480Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 11, ADC_SampleTime_480Cycles);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 12, ADC_SampleTime_480Cycles);

    ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
    ADC_DMACmd(ADC1, ENABLE);
    ADC_Cmd(ADC1, ENABLE);

    ADC_SoftwareStartConv(ADC1);

    DMA_DeInit(DMA2_Stream0);
    /* DMA2 Stream0 channel2 configuration **************************************/
    DMA_InitStructure.DMA_Channel            = DMA_Channel_0;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & (ADC1->DR); // destination
    DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)ADCValue;      // terminal
    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize         = 12;                        // 数组需要的自增次数
    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable; // 寄存器地址，即ADC1_DR_Addr不自增
    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;      // DMA_Data自增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular; // Circular according to BufferSize 16 number
    DMA_InitStructure.DMA_Priority           = DMA_Priority_High;
    // FIFO ----
    DMA_InitStructure.DMA_FIFOMode        = DMA_FIFOMode_Disable; // 不用FIFO
    DMA_InitStructure.DMA_FIFOThreshold   = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst     = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    // FIFO ----
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    DMA_Cmd(DMA2_Stream0, ENABLE);
}
/**
 * @brief 对采集的ADC值进行滤波 冒泡排序
 * @param num 第几个灰度通道
 * @return 平均之后的adc值
 */
static uint32_t Filter(uint16_t num)
{
    int i, j;
    int filter_temp, filter_sum = 0;
    int filter_buf[5];
    for (i = 0; i < 5; i++) {
        filter_buf[i] = ADCValue[num]; // 连续测量同一通道的值5次
        // 此处的延时 得科没有 行知有 具体有待实测
        // 从理论上 有这个延时能够匹配adc的采集速度
        // 从实验效果上 有这个延时好像数据更新更快 波动更小
        delay_us(20);
    }
    for (j = 0; j < 4; j++) { // 冒泡排序 从小到大
        for (i = 0; i < 4 - j; i++) {
            if (filter_buf[i] > filter_buf[i + 1]) {
                filter_temp       = filter_buf[i];
                filter_buf[i]     = filter_buf[i + 1];
                filter_buf[i + 1] = filter_temp;
            }
        }
    }
    for (i = 1; i < 5 - 1; i++) {
        filter_sum += filter_buf[i]; // 取中间三次求平均
    }
    return filter_sum / (5 - 2);
}
/**
 * @brief 返回灰度值 右边1 左边11 从右到左
 * @param ch 第几个灰度 右边1 左边11
 * @return int32_t 灰度的数值
 */
int32_t Huidu_va(uint8_t ch)
{
    static volatile uint32_t Huidu_value;
    switch (ch) {
        case 0:
            Huidu_value = Filter(4);
            break;
        case 1:
            Huidu_value = Filter(5);
            break;
        case 2:
            Huidu_value = Filter(7);
            break;
        case 3:
            Huidu_value = Filter(6);
            break;
        case 4:
            Huidu_value = Filter(11);
            break;
        case 5:
            Huidu_value = Filter(3);
            break;
        case 6:
            Huidu_value = Filter(10);
            break;
        case 7:
            Huidu_value = Filter(2);
            break;
        case 8:
            Huidu_value = Filter(9);
            break;
        case 9:
            Huidu_value = Filter(1);
            break;
        case 10:
            Huidu_value = Filter(8);
            break;
        case 11:
            Huidu_value = Filter(0);
            break;
        default:
            Huidu_value = 0;
            break;
    }
    return Huidu_value;
}

/**
 * @brief 获得灰度值, 判白线数量
 */
void get_huidu_va(void)
{
    uint8_t i;
    Gray_sum       = 0;
    sum            = 0.0;
    cnt_whiteline  = 0;
    cnt_whitelineL = 0;
    cnt_whitelineR = 0;
    for (i = 0; i < 12; i++) {
        sum += Filter(i);
        if (Filter(i) > thr_whiteline) {
            cnt_whiteline++;
        }
        if ((i < 5) && (Huidu_va(i) > thr_whiteline)) {
            cnt_whitelineR++;
        }
        if ((i >= 7) && (Huidu_va(i) > thr_whiteline)) {
            cnt_whitelineL++;
        }
    }
}